/*
 *    Description:  ip connection
 *          Author:  dimmalex (dim), dimmalex@gmail.com
 *      Company:  HP
 */

#include "land/farm.h"
#include "landnet/landnet.h"
#include <ifaddrs.h>



/* set the dial failed to restart system */
static int count_failed( const char *obj, talk_t failed )
{
    int recon2reboot;
    int reconfailed;
    const char *ptr;

	reconfailed = count_get( obj, "reconfailed" );

    /* get the count max configure */
    recon2reboot = 0;
    ptr = json_get_string( failed, "recon2reboot" );
    if ( ptr != NULL && *ptr != '\0' )
    {
        recon2reboot = atoi( ptr );
    }
    if ( recon2reboot > 0 )
    {
        if ( reconfailed >= recon2reboot )
        {
            warn( "%s need to restart because reconnect maxtime(%d)", obj, reconfailed );
            count_set( obj, "reconfailed", 0 );
            com_scall( MACHINE_COM, "restart", NULL );
            return 1;
        }
    }

	if ( reconfailed > 0 )
	{
		ndebug( "%s reconnect %d time", obj, reconfailed );
	}
    return 0;
}
static boole mode_static( const char *object, const char *ifdev, const char *device, talk_t cfg, talk_t info )
{
    talk_t v;
    const char *ptr;

    /* tell the network frame online */
    json_set_string( info, "mode", "static" );
    json_set_string( info, "ifname", object );
    json_set_string( info, "ifdev", ifdev );
    json_set_string( info, "device", device );
	v = json_get_value( cfg, "static" );
    ptr = json_get_string( v, "gw" );
    if ( NULL != ptr && *ptr != '\0' )
    {
        json_set_string( info, "gw", ptr );
    }
    ptr = json_get_string( v, "dns" );
    if ( NULL != ptr && *ptr != '\0' )
    {
        json_set_string( info, "dns", ptr );
    }
    ptr = json_get_string( v, "dns2" );
    if ( NULL != ptr && *ptr != '\0' )
    {
        json_set_string( info, "dns2", ptr );
    }
    ptr = json_get_string( v, "domain" );
    if ( NULL != ptr && *ptr != '\0' )
    {
        json_set_string( info, "domain", ptr );
    }

    return true;
}
static boole method_manual( const char *object, const char *ifdev, const char *device, talk_t cfg, talk_t info )
{
    talk_t v;
    const char *ptr;

    /* tell the network frame online */
    json_set_string( info, "method", "manual" );
    json_set_string( info, "ifname", object );
    json_set_string( info, "ifdev", ifdev );
    json_set_string( info, "device", device );
	v = json_get_value( cfg, "manual" );
    ptr = json_get_string( v, "hop" );
    if ( NULL != ptr && *ptr != '\0' )
    {
        json_set_string( info, "hop", ptr );
    }
    ptr = json_get_string( v, "resolve" );
    if ( NULL != ptr && *ptr != '\0' )
    {
        json_set_string( info, "resolve", ptr );
    }
    ptr = json_get_string( v, "resolve2" );
    if ( NULL != ptr && *ptr != '\0' )
    {
        json_set_string( info, "resolve2", ptr );
    }

    return true;
}



const char *_intro( obj_t this, param_t param )
{
    const char *obj;
    const char *str = \
"{"\
"\n    \"setup\":\"setup the ifname\","\
"\n    \"shut\":\"shutdown the ifname\","\
"\n    \"ifdev\":\"get the ifdev\","\
"\n    \"device\":\"get the device\","\
"\n    \"status\":\"get the status\""\
"\n}\n";
    obj = obj_name( this );
    if ( obj == NULL )
    {
        return NULL;
    }
    else if ( 0 == strcmp( obj, COM_ID ) )
    {
        return NULL;
    }
    return str;
}
talk_t _setup( obj_t this, param_t param )
{
    talk_t v;
    talk_t cfg;
    talk_t ret;
    const char *ptr;
    const char *obj;
    const char *object;
    char buf[IDENTIFY_SIZE];
    char ifdev[IDENTIFY_SIZE];
    char path[PATHNAME_SIZE];

    /* get the com name */
    obj = obj_name( this );
    if ( 0 == strcmp( obj, COM_ID ) )
    {
        return tfalse;
    }
    object = obj_string( this );
    /* get the ifname configure */
    cfg = config_get( this, NULL ); 
    /* exit when the status is disable */
    ptr = json_get_string( cfg, "status" );
    if ( ptr != NULL && 0 == strcmp( ptr, "disable" ) )
    {
        talk_free( cfg );
        return tfalse;
    }
    /* get the ifdev */
    if ( ifdev_get( object, ifdev, sizeof(ifdev) ) == NULL )
    {
        talk_free( cfg );
        return tfalse;
    }
	if ( com_sexist( ifdev, NULL ) == false )
	{
        talk_free( cfg );
        return tfalse;
	}
    /* setup record file, avoid duplicate setup */
    project_var_path( path, sizeof(path), PROJECT_ID, "%s.st", obj );
    v = json_load( path );
    if ( v != NULL )
    {
        ndebug( "%s already startup", object );
        talk_free( v );
        talk_free( cfg );
        return ttrue;
    }
    v = json_create();
    snprintf( buf, sizeof(buf), "%lu", time(NULL) );
    json_set_string( v, "starttime", buf );
    json_save( v , path );
    talk_free( v );

    /* run the app connection */
    ret = tfalse;
    info( "%s startup", object );
    if ( serv_start( this, "service", NULL, object ) == true )
    {
        ret = ttrue;
    }

    talk_free( cfg );
    return ret;
}
talk_t _shut( obj_t this, param_t param )
{
    talk_t v;
    talk_t cfg;
    const char *obj;
    const char *object;
    char ifdev[IDENTIFY_SIZE];
    char path[PATHNAME_SIZE];

    /* get the com name */
    obj = obj_name( this );
    if ( 0 == strcmp( obj, COM_ID ) )
    {
        return tfalse;
    }
    object = obj_string( this );
    /* delete setup record file */
    project_var_path( path, sizeof(path), PROJECT_ID, "%s.st", obj );
    v = json_load( path );
    if ( v == NULL )
    {
        return tfalse;
    }
    talk_free( v );
    unlink( path );
    /* get the configure */
    cfg = config_get( this, NULL ); 
    if ( cfg == NULL )
    {
        return tfalse;
    }
    info( "%s shut", object );
    /* call the offline */
    com_srun( NETWORK_COM, "offline", object );
    /* stop the service */
    serv_stop( "%s-ipv4", object );
    serv_stop( "%s-ipv6", object );
    serv_stop( "%s", object );
    /* tell the ifdev down */
    if ( ifdev_get( object, ifdev, sizeof(ifdev) ) != NULL )
    {
        com_scall( ifdev, "down", NULL );
    }
	/* clear the reconnect count */
	count_set( object, "reconfailed", 0 );

    talk_free( cfg );
    return ttrue;
}
talk_t _service( obj_t this, param_t param )
{
    int click;
    int check;
    talk_t v;
    talk_t cfg;
    talk_t info;
	boole persist;
	boole castup;
    const char *ptr;
    const char *obj;
    const char *object;
	const char *mode;
	const char *method;
    char ifdev[IDENTIFY_SIZE];
    char device[IDENTIFY_SIZE];

    /* get the com name */
    obj = obj_name( this );
    if ( 0 == strcmp( obj, COM_ID ) )
    {
        return tfalse;
    }
    object = obj_string( this );
    /* offline to clear first */
    serv_stop( "%s-ipv4", object );
    serv_stop( "%s-ipv6", object );
    if ( com_srun( NETWORK_COM, "extern", object ) == ttrue )
    {
        com_srun( NETWORK_COM, "offline", object );
    }
    /* get the configure */
    cfg = config_get( this, NULL ); 
    if ( cfg == NULL )
    {
        sleep( 10 );
        return tfalse;
    }
	/* get the mode and method */
	mode = json_get_string( cfg, "mode" );
	method = json_get_string( cfg, "method" );
	/* get the ifdev */
    if ( ifdev_get( object, ifdev, sizeof(ifdev) ) == NULL )
    {
        talk_free( cfg );
        sleep( 5 );
        return tfalse;
    }
	if ( com_sexist( ifdev, NULL) == false )
	{
        talk_free( cfg );
        sleep( 5 );
        return tfalse;
	}
    /* failed to restart */
    v = json_get_value( cfg, "failed" );
    if ( count_failed( object, v ) != 0 )
    {
        talk_free( cfg );
        return tfalse;
    }
	/* set the ifname to cfg for the ifdev */
	json_set_string( cfg, "ifname", object );

    /* setting the ifdev up, wisp take this cfg */
    ndebug( "%s up", ifdev );
    if ( com_sgo( ifdev, "up", cfg ) != ttrue )
    {
        fault( "%s up failed", ifdev );
        talk_free( cfg );
        sleep( 3 );
        return tfalse;
    }
    /* connect */
    ndebug( "%s connect", ifdev );
    if ( com_scall( ifdev, "connect", NULL ) != ttrue )
    {
        fault( "%s connect failed", ifdev );
        talk_free( cfg );
        sleep( 3 );
        return tfalse;
    }
    /* get the ifdev device */
    if ( com_scalls( ifdev, "device", NULL, device, sizeof(device) ) == NULL )
    {
        fault( "%s device get error", ifdev );
        talk_free( cfg );
        sleep( 3 );
        return tfalse;
    }
    /* set the mac */
    ptr = json_get_string( cfg, "mac" );
    if ( ptr != NULL && *ptr != '\0' )
    {
        com_srun( ifdev, "setmac", ptr );
    }

	/* SLAAC setting for IPv6 */
	if ( method != NULL && 0 == strcmp( method, "slaac" ) )
	{
		slaac_ip_enable( device );
	}
	else if ( method != NULL && 0 == strcmp( method, "disable" ) )
	{
		slaac_ip_disable( device );
	}

	/* static ip setting for IPv4 */
	if ( mode != NULL && 0 == strcmp( mode, "static" ) )
	{
		/* set the static ip */
		v = json_get_value( cfg, "static" );
		static_ip_enable( device, v );
	}
	else if ( mode != NULL && 0 == strcmp( mode, "dhcpc" ) )
	{
		v = json_get_value( cfg, "dhcpc" );
		ptr = json_get_string( v, "static" );
		if ( ptr != NULL && 0 == strcmp( ptr, "enable" ) )
		{
			v = json_get_value( cfg, "static" );
			static_ip_enable( device, v );
		}
	}

	/* static ip setting for IPv6 */
	if ( method != NULL && 0 == strcmp( method, "manual" ) )
	{
		/* set the static ip */
		v = json_get_value( cfg, "manual" );
		manual_ip_enable( device, v );
	}
	else if ( method != NULL && 0 == strcmp( method, "automatic" ) )
	{
		v = json_get_value( cfg, "automatic" );
		ptr = json_get_string( v, "manual" );
		if ( ptr != NULL && 0 == strcmp( ptr, "enable" ) )
		{
			v = json_get_value( cfg, "manual" );
			manual_ip_enable( device, v );
		}
	}

    /* count failed */
    count_plus( object, "reconfailed" );
    /* check connected */
    click = 0;
    check = 0;
    while( check < 30 )
    {
		/* test the ifdev connected, wisp take this cfg */
        if ( com_sgo( ifdev, "connected", cfg ) == ttrue )
        {
            click++;
            if ( click >= 5 )
            {
                ndebug( "%s connected ready", ifdev );
                break;
            }
            usleep( 300000 );
            continue;
        }
        click = 0;
        check++;
        sleep( 1 );
    }
    if ( check >= 30 )
    {
        warn( "%s connect timeout", ifdev );
        com_scall( ifdev, "down", NULL );
		talk_free( cfg );
		return tfalse;
    }

	/* many process */
	info = json_create();
	persist = castup = false;

	/* static setting */
	if ( mode != NULL && 0 == strcmp( mode, "static" ) )
	{
		if ( mode_static( object, ifdev, device, cfg, info ) == true )
		{
			castup = true;
		}
	}
	if ( method != NULL && 0 == strcmp( method, "manual" ) )
	{
		if ( method_manual( object, ifdev, device, cfg, info ) == true )
		{
			castup = true;
		}
	}

	/* automatic setting */
	if ( mode != NULL && 0 == strcmp( mode, "dhcpc" ) )
	{
		persist = true;
		ndebug( "%s dhcp connect starting", ifdev );
		joint_casts( "network/lining", object );
		v = json_get_value( cfg, "static" );
		dhcp_client_connect( object, ifdev, device, v );
	}
	if ( method != NULL && 0 == strcmp( method, "automatic" ) )
	{
		persist = true;
		ndebug( "%s dhcpv6 connect starting", ifdev );
		joint_casts( "network/lining", object );
		v = json_get_value( cfg, "static" );
		dhcpv6_client_connect( object, ifdev, device, v );
	}

	/* pppoe setting */
	if ( mode != NULL && 0 == strcmp( mode, "pppoec" ) )
	{
		persist = true;
		ndebug( "%s pppoe connect starting", ifdev );
		joint_casts( "network/lining", object );
		v = json_get_value( cfg, "pppoec" );
		pppoe_client_connect( object, ifdev, device, v );
	}

	if ( castup == true )
	{
		com_sgo( NETWORK_COM, "online", info );
	}
    talk_free( info );
	if ( persist == false )
	{
		serv_off( object );
	}
    talk_free( cfg );
    return ttrue;
}



talk_t _online( obj_t this, param_t param )
{
    talk_t v;
    talk_t cfg;
    talk_t info;
    const char *ptr;
    const char *obj;
    const char *object;
    const char *ifdev;
    const char *device;
    const char *dns;
    const char *dns2;
    char path[PATHNAME_SIZE];

    obj = obj_name( this );
    if ( 0 == strcmp( obj, COM_ID ) )
    {
        return tfalse;
    }
    object = obj_string( this );
    /* get the configure */
    cfg = config_get( this, NULL ); 
    if ( cfg == NULL )
    {
        return tfalse;
    }
    /* get info */
    info = param_talk( param, 1 );
    device = json_get_string( info, "device" );
    if ( device == NULL )
    {
        return tfalse;
    }
    ifdev = json_get_string( info, "ifdev" );
    /* dns */
    dns = json_get_string( info, "dns" );
    dns2 = json_get_string( info, "dns2" );
    /* custom dns */
	v = NULL;
    ptr = json_get_string( cfg, "mode" );
    if ( ptr != NULL )
    {
        v = json_get_value( cfg, ptr );
        ptr = json_get_string( v, "custom_dns" );
        if ( ptr != NULL && 0 == strcmp( ptr, "enable" ) )
        {
            dns = json_get_string( v, "dns" );
            dns2 = json_get_string( v, "dns2" );
        }
    }
    ptr = json_get_string( info, "domain" );
    if ( (ptr != NULL && *ptr != '\0')
        || (dns != NULL && *dns != '\0') 
        || (dns2 != NULL && *dns2 != '\0') 
        )
    {
        snprintf( path, sizeof(path), "%s/%s", RESOLV_DIR, object );
        unlink( path );
        if ( ptr != NULL && *ptr != '\0' )
        {
            append_string( path, "search %s\n", ptr );
        }
        if ( dns != NULL && *dns != '\0'  )
        {
            append_string( path, "nameserver %s\n", dns );
            /* the ifname resolv may cannot work at other ifname */
            route_switch( NULL, dns, NULL, true, info );
        }
        if ( dns2 != NULL && *dns2 != '\0'  )
        {
            append_string( path, "nameserver %s\n", dns2 );
            /* the ifname resolv may cannot work at other ifname */
            route_switch( NULL, dns2, NULL, true, info );
        }
    }
    /* masq */
    ndebug( "shell( iptables -t nat -D %s -o %s -j MASQUERADE >/dev/null 2>&1 )", MASQ_CHAIN, device );
    shell( "iptables -t nat -D %s -o %s -j MASQUERADE >/dev/null 2>&1", MASQ_CHAIN, device );
    ptr = json_get_string( cfg, "masq" );
    if ( ptr != NULL && 0 == strcmp( ptr, "enable" ) )
    {
        ndebug( "shell( iptables -t nat -A %s -o %s -j MASQUERADE )", MASQ_CHAIN, device );
        shell( "iptables -t nat -A %s -o %s -j MASQUERADE", MASQ_CHAIN, device );
    }
    /* ppp tcp mss */
    if ( 0 == strncmp( device, "ppp", 3 ) )
    {
        ptr = json_get_string( v, "txqueuelen" );
        if ( ptr == NULL || *ptr == '\0' )
        {
            ptr = "500";
        }
        ndebug( "shell( ifconfig %s txqueuelen %s)", device, ptr );
        ndebug( "shell( iptables -t mangle -D POSTROUTING -o %s -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:1536 -j TCPMSS --clamp-mss-to-pmtu )", device );
        ndebug( "shell( iptables -t mangle -A POSTROUTING -o %s -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:1536 -j TCPMSS --clamp-mss-to-pmtu )", device );
        shell( "ifconfig %s txqueuelen %s", device, ptr );
        shell( "iptables -t mangle -D POSTROUTING -o %s -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:1536 -j TCPMSS --clamp-mss-to-pmtu >/dev/null 2>&1", device );
        shell( "iptables -t mangle -A POSTROUTING -o %s -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:1536 -j TCPMSS --clamp-mss-to-pmtu", device );
    }
    /* tell the ifdev */
    if ( ifdev != NULL )
    {
        com_srun( ifdev, "online", object );
    }
    /* clear the failed count, dnon't clear at the icmp keeplive(clear in the keeplive) */
    info = json_get_value( cfg, "keeplive" );
    ptr = json_get_string( info, "type" );
    if ( ptr == NULL || 0 != strcmp( ptr, "icmp" ) )
    {
		count_set( object, "reconfailed", 0 );
    }

    talk_free( cfg );
    return ttrue;
}
talk_t _offline( obj_t this, param_t param )
{
    talk_t cfg;
    talk_t info;
    const char *ptr;
    const char *obj;
    const char *object;
    const char *device;
    const char *ifdev;
    char path[PATHNAME_SIZE];

    /* get the com name */
    obj = obj_name( this );
    if ( 0 == strcmp( obj, COM_ID ) )
    {
        return tfalse;
    }
    object = obj_string( this );
    /* get the configure */
    cfg = config_get( this, NULL ); 
    if ( cfg == NULL )
    {
        return tfalse;
    }
    /* get info */
    info = param_talk( param, 1 );
    device = json_get_string( info, "device" );
    if ( device == NULL )
    {
        return tfalse;
    }
    /* dns file */
    snprintf( path, sizeof(path), "%s/%s", RESOLV_DIR, object );
    unlink( path );
    /* masq */
    ptr = json_get_string( cfg, "masq" );
    if ( ptr != NULL && 0 == strcmp( ptr, "enable" ) )
    {
        ndebug( "shell( iptables -t nat -D %s -o %s -j MASQUERADE >/dev/null 2>&1 )", MASQ_CHAIN, device );
        shell( "iptables -t nat -D %s -o %s -j MASQUERADE >/dev/null 2>&1", MASQ_CHAIN, device );
    }
    /* ppp tcp mss */
    if ( 0 == strncmp( device, "ppp", 3 ) )
    {
        ndebug( "shell( iptables -t mangle -D POSTROUTING -o %s -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:1536 -j TCPMSS --clamp-mss-to-pmtu >/dev/null 2>&1 )", device );
        shell( "iptables -t mangle -D POSTROUTING -o %s -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:1536 -j TCPMSS --clamp-mss-to-pmtu >/dev/null 2>&1", device );
    }
    /* tell the ifdev */
    ifdev = json_get_string( info, "ifdev" );
    if ( ifdev != NULL )
    {
        com_srun( ifdev, "offline", object );
    }

    talk_free( cfg );
    return ttrue;
}
talk_t _ifdev( obj_t this, param_t param )
{
    const char *obj;
    const char *object;
    char ifdev[IDENTIFY_SIZE];

    obj = obj_name( this );
    if ( 0 == strcmp( obj, COM_ID ) )
    {
        return NULL;
    }
    object = obj_string( this );
    if ( ifdev_get( object, ifdev, sizeof(ifdev) ) != NULL )
    {
        return phrase_create( ifdev );
    }
    return NULL;
}
talk_t _device( obj_t this, param_t param )
{
    talk_t ret;
    talk_t info;
    const char *obj;
    const char *object;
    char ifdev[PATHNAME_SIZE];
    char path[PATHNAME_SIZE];

    obj = obj_name( this );
    if ( 0 == strcmp( obj, COM_ID) )
    {
        return NULL;
    }
    object = obj_string( this );
    project_var_path( path, sizeof(path), NETWORK_PROJECT, "%s.ol", object );
    info = json_load( path );
    ret = json_cut_value( info, "device" );
    if ( ret == NULL )
    {
        if ( ifdev_get( object, ifdev, sizeof(ifdev) ) != NULL )
        {
            ret = com_scall( ifdev, "device", NULL );
        }
    }
    talk_free( info );
    return ret;
}
talk_t _status( obj_t this, param_t param )
{
    talk_t ret;
    talk_t cfg;
    talk_t info;
    struct stat st;
    boole keeplive;
    const char *ptr;
    const char *obj;
    const char *object;
    const char *device;
    char ifdev[PATHNAME_SIZE];
    char buf[PATHNAME_SIZE];

    /* get the com name */
    obj = obj_name( this );
    if ( 0 == strcmp( obj, COM_ID ) )
    {
        return tfalse;
    }
    object = obj_string( this );
    ret = NULL;
    /* get the configure */
    cfg = config_get( this, NULL ); 
    ifdev_get( object, ifdev, sizeof(ifdev) );
    /* get the keeplive config */
    keeplive = false;
    info = json_get_value( cfg, "keeplive" );
    ptr = json_get_string( info, "type" );
    if ( ptr != NULL && 0 == strcmp( ptr, "icmp" ) )  //dns will failed because dhcps need it ok to full the dns host
    {
        keeplive = true;
    }
    /* get the online status */
    project_var_path( buf, sizeof(buf), NETWORK_PROJECT, "%s.ol", object );
    if ( stat( buf, &st ) != 0 )
    {
        ret = json_create();
		if ( com_sexist( ifdev, "device" ) == true )
		{
	        device = com_scalls( ifdev, "device", NULL, NULL, 0 );
	        if ( device != NULL )
	        {
	            json_set_string( ret, "device", device );
	            if ( netcard_info( device, NULL, 0, NULL, 0, NULL, 0, buf, sizeof(buf) ) == 0 )
	            {
	                json_set_string( ret, "mac", buf );
	            }
	        }
		}
        if ( serv_pid( object ) >= 0 )
        {
            json_set_string( ret, "status", "uping" );
        }
        else
        {
            json_set_string( ret, "status", "down" );
        }
    }
    else
    {
        char ip[16];
        char dstip[16];
        char mask[16];
        unsigned long long rt_bytes, rt_packets, rt_errs, rt_drops, tt_bytes, tt_packets, tt_errs, tt_drops;
        ip[0] = dstip[0] = mask[0] = '\0';
        rt_bytes = rt_packets = rt_errs = rt_drops = tt_bytes = tt_packets = tt_errs = tt_drops = 0;
        ret = json_load( buf );
        device = json_get_string( ret, "device" );

		/* IPv4 */
        netcard_info( device, ip, sizeof(ip), dstip, sizeof(dstip), mask, sizeof(mask), NULL, 0 );
        if ( netcard_isflags( device, IFF_UP ) == 0 || *ip == '\0' )
        {
            if ( serv_pid( object ) >= 0 )
            {
                json_set_string( ret, "status", "uping" );
            }
            else
            {
                json_set_string( ret, "status", "down" );
            }
        }
        else
        {
            json_set_string( ret, "status", "up" );
            json_set_string( ret, "ip", ip );
            json_set_string( ret, "dstip", dstip );
            json_set_string( ret, "mask", mask );
            /* custom dns */
            ptr = json_get_string( cfg, "mode" );
            if ( ptr != NULL )
            {
                info = json_get_value( cfg, ptr );
                ptr = json_get_string( info, "custom_dns" );
                if ( ptr != NULL && 0 == strcmp( ptr, "enable" ) )
                {
                    json_set_string( ret, "dns", json_get_string( info, "dns" ) );
                    json_set_string( ret, "dns2", json_get_string( info, "dns2" ) );
                }
            }
			/* ipv6 */
            ptr = json_get_string( cfg, "method" );
            if ( ptr != NULL && *ptr != '\0' && 0 != strcmp( ptr, "disable" ) )
            {
				int t;
            	int rc;
				char addrname[IDENTIFY_SIZE];
				char host[NI_MAXHOST];
				struct sockaddr_in6 *in6;
            	struct ifaddrs *ifaddr, *ifa;
				json_set_string( ret, "method", ptr );
				if ( getifaddrs( &ifaddr ) == 0 )
				{
					t = 1;
					for ( ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next )
					{
						in6 = (struct sockaddr_in6 *)ifa->ifa_addr;
						if ( ifa->ifa_addr == NULL )
						{
							continue;
						}
						if ( ifa->ifa_addr->sa_family != AF_INET6 )
						{
							continue;
						}
						if ( 0 != strcmp( ifa->ifa_name, device ) )
						{
							continue;
						}
						rc = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
						if ( rc == 0 )
						{
							if ( t <= 1 )
							{
								strcpy( addrname, "addr" );
							}
							else
							{
								sprintf( addrname, "addr%d", t );
							}
							json_set_string( ret, addrname, host );
							t++;
							//printf("dev: %-8s address: <%s> scope %d\n", ifa->ifa_name, host, in6->sin6_scope_id);
						}
					}
					freeifaddrs(ifaddr);					
				}
                info = json_get_value( cfg, ptr );
                ptr = json_get_string( info, "custom_resolve" );
                if ( ptr != NULL && 0 == strcmp( ptr, "enable" ) )
                {
                    json_set_string( ret, "resolve", json_get_string( info, "resolve" ) );
                    json_set_string( ret, "resolve2", json_get_string( info, "resolve2" ) );
                }
            }
            /* get the keeplive status */
            if ( keeplive == true )
            {
                project_var_path( buf, sizeof(buf), NETWORK_PROJECT, "%s.kp", object );
                ptr = read_string( buf, NULL, 0 );
                if ( ptr == NULL || *ptr == '\0' )
                {
                    json_set_string( ret, "keeplive", "failed" );
                }
                else
                {
                    json_set_string( ret, "keeplive", ptr );
                }
            }
        }
        buf[0] = '\0';
        netcard_info( device, NULL, 0, NULL, 0, NULL, 0, buf, sizeof(buf) );
        if ( *buf == '\0' || 0 == strcmp( buf, "00:00:00:00:00:00" ) || 0 == strcasecmp( buf, "ff:ff:ff:ff:ff:ff" ) ) // ppp interface mac
        {
            ptr = com_scalls( ifdev, "device", NULL, NULL, 0 );
            netcard_info( ptr, NULL, 0, NULL, 0, NULL, 0, buf, sizeof(buf) );
        }
        json_set_string( ret, "mac", buf );
        netcard_flew( device, &rt_bytes, &rt_packets, &rt_errs, &rt_drops, &tt_bytes, &tt_packets, &tt_errs, &tt_drops );
        snprintf( buf, sizeof(buf), "%llu", rt_bytes );
        json_set_string( ret, "rx_bytes", buf );
        snprintf( buf, sizeof(buf), "%llu", rt_packets );
        json_set_string( ret, "rx_packets", buf );
        snprintf( buf, sizeof(buf), "%llu", tt_bytes );
        json_set_string( ret, "tx_bytes", buf );
        snprintf( buf, sizeof(buf), "%llu", tt_packets );
        json_set_string( ret, "tx_packets", buf );
    }
    /* get the mode of configure */
    json_set_string( ret, "mode", json_get_string( cfg, "mode" ) );
    /* get the ifdev info */
    info = NULL;
	if ( (com_sexist( ifdev, "status" ) == true) && (NULL != ( info = com_srun( ifdev, "status", object ) )) )
	{
	    ptr = json_get_string( info, "status" );
	    if ( ptr != NULL && ( 0 == strcmp( ptr, "uping" ) || 0 == strcmp( ptr, "down" ) ) )
	    {
	        json_set_string( ret, "status", ptr );
	    }
		/* only for wisp */
		ptr = json_get_string( info ,"peer" );
		if ( ptr != NULL && *ptr != '\0' )
		{
	        json_set_string( ret, "peer", ptr );
		}
		ptr = json_get_string( info ,"peermac" );
		if ( ptr != NULL && *ptr != '\0' )
		{
	        json_set_string( ret, "peermac", ptr );
		}
		ptr = json_get_string( info ,"channel" );
		if ( ptr != NULL && *ptr != '\0' )
		{
	        json_set_string( ret, "channel", ptr );
		}
		ptr = json_get_string( info ,"rate" );
		if ( ptr != NULL && *ptr != '\0' )
		{
	        json_set_string( ret, "rate", ptr );
		}
		ptr = json_get_string( info ,"sig" );
		if ( ptr != NULL && *ptr != '\0' )
		{
	        json_set_string( ret, "sig", ptr );
		}
		ptr = json_get_string( info ,"signal" );
		if ( ptr != NULL && *ptr != '\0' )
		{
	        json_set_string( ret, "signal", ptr );
		}
	    talk_free( info );
	}
    talk_free( cfg );
    /* ontime to livetime_string */
    ptr = json_get_string( ret, "ontime" );
    if ( ptr != NULL && *ptr != '\0' )
    {
        json_set_string( ret, "livetime", livetime_count( ptr, buf, sizeof(buf) ) );
    }

    return ret;
}
/* only for apclient */
talk_t _aplist( obj_t this, param_t param )
{
	talk_t ret;
	const char *obj;
	const char *object;
	char ifdev[PATHNAME_SIZE];

	obj = obj_name( this );
	if ( 0 == strcmp( obj, COM_ID) )
	{
		return NULL;
	}
	object = obj_string( this );
	ret = NULL;
	if ( ifdev_get( object, ifdev, sizeof(ifdev) ) != NULL )
	{
		ret = com_scall( ifdev, "aplist", NULL );
	}
	return ret;
}
/* only for apclient */
talk_t _radiolist( obj_t this, param_t param )
{
	talk_t ret;
	const char *obj;
	const char *object;
	char ifdev[PATHNAME_SIZE];

	obj = obj_name( this );
	if ( 0 == strcmp( obj, COM_ID) )
	{
		return NULL;
	}
	object = obj_string( this );
	ret = NULL;
	if ( ifdev_get( object, ifdev, sizeof(ifdev) ) != NULL )
	{
		ret = com_scall( ifdev, "radiolist", NULL );
	}
	return ret;
}



boole _set( obj_t this, path_t path, talk_t v )
{
    boole ret;
	const char *obj;

    ret = config_set( this, path, v );
    if ( ret == true )
    {
    	obj = obj_name( this );
		if ( NULL == strstr( obj, "lan") )
		{
	        _shut( this, NULL );
	        _setup( this, NULL );
		}
    }
    return ret;
}
talk_t _get( obj_t this, path_t path )
{
    return config_get( this, path );
}    



